#include "FpsCalculator.h"

void FpsCalculator::Reset()
{
    decltype(cache) t;
    cache.swap(t);
}

void FpsCalculator::Init(int size, std::string name, bool managed)
{
    this->size = size;
    this->name = name;
    this->managed = managed;
    if (managed)
    {
        auto self = shared_from_this();
        FpsManager::GetInstance()->AddCalculator(self);
    }
}

void FpsCalculator::SetName(std::string s)
{
    this->name = s;
}

void FpsCalculator::Add()
{
    auto t = std::chrono::high_resolution_clock::now();
    cache.emplace(t);
    if (cache.size() > size)
    {
        cache.pop();
    }
}

float FpsCalculator::Fps()
{
    if (cache.size() < 10)
    {
        return 0;
    }
    auto t = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - cache.front()).count();
    if (t == 0)
    {
        return 0;
    }
    return (cache.size() - 1) * 1000 / (float)t;
    // return 1000 / ((float)t / (cache.size() - 1)  );
}

std::string FpsCalculator::Name()
{
    return this->name;
}

FpsCalculator::~FpsCalculator()
{
    /*if (managed)
    {
        auto self = shared_from_this();
        FpsManager::GetInstance()->Remove(self);
    }*/
}

void FpsManager::AddCalculator(std::shared_ptr<FpsCalculator> calculator)
{
    std::scoped_lock<std::mutex> g(mtx);
    vec_calculators.push_back(calculator);
}

void FpsManager::Remove(std::string name)
{
    std::scoped_lock<std::mutex> g(mtx);
    for (auto iter = vec_calculators.begin(); iter != vec_calculators.end(); iter++)
    {
        if ((*iter)->Name() == name)
        {
            iter = vec_calculators.erase(iter);
        }
    }
}

void FpsManager::Remove(std::shared_ptr<FpsCalculator> calculator)
{
    std::scoped_lock<std::mutex> g(mtx);
    for (auto iter = vec_calculators.begin(); iter != vec_calculators.end(); iter++)
    {
        if ((*iter) == calculator)
        {
            iter = vec_calculators.erase(iter);
            break;
        }
    }
}

FpsManager::~FpsManager()
{
    vec_calculators.clear();
}

std::string FpsManager::Dump()
{
    std::string text = "";
    std::stringstream ss;

    int count_normal = 0;
    int count_abnormal = 0;

    if (!vec_calculators.empty())
    {
        auto doc = nlohmann::json::array();
        for (auto iter = vec_calculators.begin(); iter != vec_calculators.end(); iter++)
        {
            auto calculator = *iter;
            auto fps = calculator->Fps();
            nlohmann::json item = { { "name", calculator->Name() }, { "fps", fmt::format("{:.1f}", fps) } };

            if (strstr(calculator->Name().c_str(), "decoder"))
            {
                if (fps > 20)
                    count_normal++;
                else
                    count_abnormal++;

                ss << fmt::format("{} : {:.1f}\n", calculator->Name(), fps);
            }

            doc.push_back(item);
        }

        text = doc.dump();

        SPDLOG_INFO(ss.str());
    }

    return text;
}